Skip to content

feat(pmoves-ai): Add PMOVES.AI integration patterns#3

Merged
POWERFULMOVES merged 4 commits intoPMOVES.AI-Edition-Hardenedfrom
feat/pmoves-ai-integration
Jan 21, 2026
Merged

feat(pmoves-ai): Add PMOVES.AI integration patterns#3
POWERFULMOVES merged 4 commits intoPMOVES.AI-Edition-Hardenedfrom
feat/pmoves-ai-integration

Conversation

@POWERFULMOVES
Copy link
Copy Markdown
Owner

@POWERFULMOVES POWERFULMOVES commented Jan 19, 2026

Summary

This PR adds PMOVES.AI integration patterns to PMOVES-Archon, enabling seamless integration with the parent PMOVES.AI platform.

Integration Components

CHIT Secrets Management

  • Added chit/secrets_manifest_v2.yaml for compressed secrets handling
  • Environment variable precedence: env vars (50) → CHIT vault (100)

Tier-Based Environment Loading

  • Added env.shared - Base PMOVES.AI service configuration (~6000 lines)
  • Added env.tier-agent.sh - Agent tier specific environment variables
  • Docker Compose YAML anchors for tier-based env loading

Service Discovery

  • Added pmoves_announcer/ - NATS service announcement module
  • Added pmoves_registry/ - Service registry client with fallback chain
  • Fallback chain: env vars → Supabase → NATS → Docker DNS

Health Endpoints

  • Added pmoves_health/ - Comprehensive health check module
  • Dependency checks for databases, HTTP services, NATS

Documentation

  • Added PMOVES.AI_INTEGRATION.md - Integration guide and checklist
  • Added docker-compose.pmoves.yml - PMOVES.AI YAML anchors

Testing

# Service health check
curl http://localhost:8091/healthz

# Verify NATS announcements
nats sub "service.announce.>"

Checklist

  • CHIT secrets manifest configured
  • Tier-based env loading implemented
  • NATS service discovery integrated
  • Health endpoints exposed
  • PMOVES.AI documentation added

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Service announcement and discovery utilities for PMOVES services.
    • Health check orchestration with pluggable dependency checks (DB, HTTP, NATS).
    • Service registry with env-var overrides and DNS fallback plus health probing.
  • Documentation

    • New PMOVES.AI integration guide for Archon Agent Service.
  • Chores

    • Secrets manifest template.
    • Docker Compose templates for standardized env and health/monitoring.
    • Shared and tier-specific environment configuration templates.

✏️ Tip: You can customize this high-level summary in your review settings.

- Add CHIT secrets manifest (chit/secrets_manifest_v2.yaml)
- Add tier-based environment loading (env.shared, env.tier-agent.sh)
- Add health check module (pmoves_health/)
- Add NATS service announcer (pmoves_announcer/)
- Add service registry client (pmoves_registry/)
- Add Docker Compose YAML anchors (docker-compose.pmoves.yml)
- Add integration documentation (PMOVES.AI_INTEGRATION.md)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 19, 2026

Warning

Rate limit exceeded

@POWERFULMOVES has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 40 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
bad indentation of a mapping entry in ".coderabbit.yaml" (11:3)

  8 |   excluded_branches:
  9 |     - "origin/main"
 10 | language: "en-US"
 11 |   doc_target_coverage: 80
--------^
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

Adds PMOVES.AI integration assets: documentation, secrets manifest, Docker Compose anchors, shared and agent-tier env files, and three new Python libraries for service announcing (NATS), health checking (with optional FastAPI), and service registry/discovery.

Changes

Cohort / File(s) Summary
Documentation
PMOVES.AI_INTEGRATION.md
New integration guide describing setup, env files, compose augmentation, health check and NATS announcement workflows, testing, and created artifacts.
Secrets Manifest
chit/secrets_manifest_v2.yaml
New CHIT v2 secrets manifest template with precedence (env, CHIT Vault), required/optional variables, env-specific groups, and validation settings.
Docker Compose Anchors
docker-compose.pmoves.yml
New reusable Docker Compose anchors and templates for env loading, tier-specific anchors (api, agent, worker, data, llm, media), healthchecks, GPU resources, and Prometheus labels; includes commented examples.
Shared Env
env.shared
New base environment file exporting defaults for PMOVES services (identifiers, NATS, TensorZero, GPU orchestrator, data services, Supabase, monitoring, Archon, proxies, vault, timeouts, health checks).
Agent Tier Env
env.tier-agent.sh
New agent-tier shell env file exporting TIER=agent and agent-specific defaults (concurrency, timeouts, task queue, MCP, state backend, LLM defaults, prompt/cache settings).
Service Announcer
pmoves_announcer/__init__.py
New module: ServiceTier enum, ServiceAnnouncement dataclass (serialize/deserialize), ServiceAnnouncer (announce, retry), announce_service helper, and BackgroundAnnouncer for periodic announcements via NATS on subject services.announce.v1.
Health Framework
pmoves_health/__init__.py
New health framework: HealthStatus constants, DependencyCheck base class and DatabaseCheck/HTTPCheck/NATSCheck, HealthChecker orchestrator, decorator/helpers, get_health_status, and optional FastAPI router/app exposing /healthz.
Service Registry
pmoves_registry/__init__.py
New service discovery: ServiceTier enum, ServiceInfo dataclass, ServiceNotFoundError, env-override and DNS fallback resolution, async APIs get_service_info, get_service_url, check_service_health, and CommonServices map.

Sequence Diagram

sequenceDiagram
    participant Service as Service Instance
    participant NATS as NATS Broker
    participant Registry as Service Registry
    participant Consumer as Consumer Service
    participant Health as Health Checker

    Service->>Service: create_announcement()
    Service->>NATS: publish(ServiceAnnouncement) on services.announce.v1
    NATS-->>NATS: distribute message

    Consumer->>Registry: get_service_info(slug)
    Registry->>Registry: check environment overrides
    alt env override found
        Registry-->>Consumer: return ServiceInfo (env)
    else
        Registry->>Registry: construct DNS fallback URL
        Registry-->>Consumer: return ServiceInfo (fallback)
    end

    Consumer->>Health: check_service_health(slug)
    Health->>Consumer: HTTP GET /healthz -> status (200/503)
    Consumer-->>Health: interpret boolean result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nibble anchors, hop through env lines,
I trumpet NATS and health-check chimes;
Registry maps the burrow's gate,
Announcements bounce—oh how great!
A tiny rabbit cheers: PMOVES takes flight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 74.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(pmoves-ai): Add PMOVES.AI integration patterns' clearly and concisely summarizes the main change—adding PMOVES.AI integration components to the codebase.
Description check ✅ Passed The PR description comprehensively covers the template requirements with all major sections completed: summary, detailed changes, type of change (new feature), affected services (Docker/Infrastructure), testing examples, and a completed checklist.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c66dd80dec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pmoves_health/__init__.py Outdated
Comment on lines +188 to +196
def health_check(checks: List[DependencyCheck] = None):
"""Decorator to add health checks to a function."""
def decorator(func: Callable):
@wraps(func)
async def wrapper(*args, **kwargs):
checker = _health_checker
if checks:
for check in checks:
checker.add_check(check)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid re-adding checks on every health request

The health_check decorator mutates the global _health_checker on every invocation by re-adding the same checks, so a long-running service that is polled frequently (e.g., k8s/Compose health checks) will keep appending duplicate checks. This makes each health request progressively slower and can lead to timeouts or unnecessary load on dependencies. Consider registering checks once at startup or deduplicating before appending.

Useful? React with 👍 / 👎.

Comment thread docker-compose.pmoves.yml
Comment on lines +38 to +43
# Agent Tier Environment
x-env-tier-agent: &env-tier-agent
<<: *pmoves-env-base
env_file:
- env.shared
- env.tier-agent # Agent tier specific configuration
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fix agent tier env_file name mismatch

The compose anchors point at env.tier-agent, but the only file added in this commit is env.tier-agent.sh. As written, the agent-tier anchor won’t load any tier-specific variables (and the referenced file doesn’t exist), so services using *env-tier-agent will miss the intended configuration. Either rename the file or update the anchor to match the actual filename.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🤖 Fix all issues with AI agents
In `@docker-compose.pmoves.yml`:
- Around line 18-97: The docker-compose uses env_file entries (x-pmoves-env /
x-env-tier-*) pointing to script-style files (env.shared, env.tier-agent, etc.)
which won't be parsed as dotenv; either convert those scripts into dotenv format
(KEY=VALUE lines with no export or ${VAR:-default} expressions) and ensure
filenames match (e.g., env.tier-agent -> env.tier-agent or update compose to
env.tier-agent.sh), or stop using env_file and instead source the .sh files
before running compose (e.g., require "source env.shared && source
env.tier-agent.sh" prior to docker compose up) or add a build step that
generates proper dotenv files from the scripts; fix references to env.tier-agent
/ env.tier-worker / env.tier-llm etc. so the filenames used in env_file exactly
match the filesystem.

In `@env.shared`:
- Around line 13-63: The env.shared file currently sets PMOVES_ENV to production
and provides insecure default credentials (e.g., NEO4J_USERNAME/NEO4J_PASSWORD,
MINIO_ACCESS_KEY/MINIO_SECRET_KEY); change these defaults so production is not
the implicit default and credentials are not filled: set PMOVES_ENV to a
non-production default (e.g., development) or require explicit override, and
replace sensitive defaults for NEO4J_PASSWORD, MINIO_SECRET_KEY,
MINIO_ACCESS_KEY (and any other credentials like MEILISEARCH_API_KEY,
QDRANT_API_KEY) with empty values or a clear sentinel like "CHANGE_ME" so
deployers must supply secure credentials; ensure documentation/validation
enforces providing real secrets for production environments referenced by the
SERVICE_NAME/SERVICE_SLUG variables.

In `@env.tier-agent.sh`:
- Around line 1-4: env.tier-agent.sh is missing a shell directive which triggers
ShellCheck SC2148; add a POSIX-compatible shebang as the first line of
env.tier-agent.sh (for example using env to pick bash) so the script has a
declared shell and CI/ShellCheck will pass, and verify the file starts with that
line and is saved with proper line endings.

In `@envared`:
- Around line 51-63: Remove hard-coded default credentials and force explicit
overrides: stop assigning defaults for NEO4J_USERNAME, NEO4J_PASSWORD,
MEILISEARCH_API_KEY, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY in the env file (do
not default to "neo4j"/"minioadmin"/empty API keys); instead leave them unset or
empty and add startup validation logic that checks these environment variables
and fails fast with a clear error if they are missing. Also avoid defaulting
PMOVES_ENV to "production" without explicit intent—require it be set or validate
allowed values at startup. Use the environment variable names (NEO4J_USERNAME,
NEO4J_PASSWORD, MEILISEARCH_API_KEY, MINIO_ACCESS_KEY, MINIO_SECRET_KEY,
PMOVES_ENV) to locate and change the assignments and to implement the
validation.

In `@pmoves_announcer/__init__.py`:
- Around line 7-9: Update the usage snippet in __init__.py to import from the
correct package name: change the example that currently says "from
service_announcer import ServiceAnnouncer, announce_service" so it references
the actual module "pmoves_announcer" and still mentions the exported symbols
ServiceAnnouncer and announce_service; ensure the docstring/usage block
consistently shows "from pmoves_announcer import ServiceAnnouncer,
announce_service" so consumers see the correct import path.
- Around line 169-185: Replace the insecure print in the announcement error
handler with structured logging that does not interpolate the raw exception or
the nats_url; inside the except block (surrounding ServiceAnnouncement creation
and NATS.connect calls) call your module or instance logger (e.g., logger.error)
with a sanitized message like "Failed to announce service" and attach
non-sensitive context such as the exception class name (type(e).__name__) or an
error code rather than e.__str__(), ensuring no NATS URL or credentials are
logged; keep returning False after logging.

In `@pmoves_health/__init__.py`:
- Around line 188-198: The decorator health_check currently mutates
_health_checker by calling checker.add_check(check) inside wrapper on every
invocation, causing duplicate checks; move the logic that registers checks to
decoration time (inside decorator before defining wrapper) or guard for
duplicates there — e.g., iterate over the provided checks once in health_check's
decorator scope and call _health_checker.add_check(check) (or check existing
_health_checker.checks to avoid duplicates) so wrapper only calls func and does
not modify _health_checker on each call.

In `@pmoves_registry/__init__.py`:
- Around line 4-9: The module header claims a 4-step fallback chain (env,
Supabase, NATS, Docker DNS) but get_service_info only uses environment variables
and DNS; update the implementation or the docstring to match reality. Either
implement Supabase lookups and NATS announcements in get_service_info (add a
Supabase client call to query the service catalog by service name and a NATS
subscriber/cache lookup to check recent announcements, using identifiable
functions like get_service_info and any existing cache/NATS helper), or simplify
the module docstring to list only the actually-implemented fallbacks (env and
DNS) and remove Supabase/NATS from the header. Ensure references to
get_service_info and any new helpers are consistent and add minimal error
handling/logging around external calls.
- Around line 147-166: The env-override branch that constructs ServiceInfo when
_get_env_url(slug) returns a base URL must ensure health_check_url points to a
health endpoint rather than the bare base (modify the ServiceInfo creation in
the env block that builds slug/name/health_check_url); detect if env_url already
ends with a known health suffix (e.g., "/health", "/healthz", "/status",
"/ready") and use it as-is, otherwise append "/healthz" (preserving any trailing
slash behavior) before assigning health_check_url so check_service_health won't
404.

In `@PMOVES.AI_INTEGRATION.md`:
- Around line 73-78: The markdown list item for "Health Check" uses a bare URL
which violates MD034; update the list item "- **Health Check:**
http://localhost:8091/healthz" to use angle-bracket or link syntax (e.g., "-
**Health Check:** <http://localhost:8091/healthz>" or "- **Health Check:**
[http://localhost:8091/healthz](http://localhost:8091/healthz)") so the URL is
not bare and MD034 is satisfied.
- Around line 13-15: Update the docs to reference the correct filename
`env.tier-agent.sh` (replace the incorrect `env.tier-agent`) and hyphenate
“tier-specific” everywhere; locate the list entry that currently reads
`env.tier-agent - AGENT tier specific configuration` and change it to
`env.tier-agent.sh - AGENT tier-specific configuration`.
🧹 Nitpick comments (3)
pmoves_registry/__init__.py (1)

40-63: Validate env/DNS-derived ServiceInfo with Pydantic.
ServiceInfo is built from external strings (env/DNS) without validation; malformed URLs can slip through and fail later. Consider a Pydantic model (e.g., AnyUrl for health_check_url, constrained slug) to raise validation errors early. As per coding guidelines, use Pydantic to raise validation errors for bad data.

pmoves_announcer/__init__.py (1)

88-102: Use Pydantic to validate announcement payloads.
from_json accepts untrusted data and will either silently coerce types or raise KeyError/ValueError later. A Pydantic model (e.g., AnyUrl for url/health_check, constrained port) can fail fast and return actionable errors. As per coding guidelines, use Pydantic to raise validation errors for bad data.

pmoves_health/__init__.py (1)

72-105: Validate HTTP/NATS URLs instead of masking bad inputs.
Invalid URLs are currently swallowed and reported as False, which hides configuration errors. Consider Pydantic validation (e.g., AnyUrl) at registration time to raise clear errors. As per coding guidelines, use Pydantic to raise validation errors for bad data.

Comment thread docker-compose.pmoves.yml Outdated
Comment on lines +18 to +97
x-pmoves-env: &pmoves-env-base
env_file:
- env.shared # Base PMOVES.AI configuration
environment:
- PMOVES_ENV=${PMOVES_ENV:-production}
- TIER=${TIER}
- NATS_URL=${NATS_URL:-nats://nats:4222}
- TENSORZERO_URL=${TENSORZERO_URL:-http://tensorzero-gateway:3030}

# API Tier Environment
x-env-tier-api: &env-tier-api
<<: *pmoves-env-base
env_file:
- env.shared
- env.tier-api # API tier specific configuration
environment:
- TIER=api
- MAX_CONCURRENT_REQUESTS=${MAX_CONCURRENT_REQUESTS:-100}
- RATE_LIMIT_ENABLED=${RATE_LIMIT_ENABLED:-true}

# Agent Tier Environment
x-env-tier-agent: &env-tier-agent
<<: *pmoves-env-base
env_file:
- env.shared
- env.tier-agent # Agent tier specific configuration
environment:
- TIER=agent
- MAX_CONCURRENT_AGENTS=${MAX_CONCURRENT_AGENTS:-50}
- MCP_ENABLED=${MCP_ENABLED:-true}

# Worker Tier Environment
x-env-tier-worker: &env-tier-worker
<<: *pmoves-env-base
env_file:
- env.shared
- env.tier-worker # Worker tier specific configuration
environment:
- TIER=worker
- MAX_CONCURRENT_JOBS=${MAX_CONCURRENT_JOBS:-10}
- WORKER_POOL_SIZE=${WORKER_POOL_SIZE:-4}

# Data Tier Environment
x-env-tier-data: &env-tier-data
<<: *pmoves-env-base
env_file:
- env.shared
- env.tier-data # Data tier specific configuration
environment:
- TIER=data
- MAX_CONNECTIONS=${MAX_CONNECTIONS:-100}

# LLM Tier Environment
x-env-tier-llm: &env-tier-llm
<<: *pmoves-env-base
env_file:
- env.shared
- env.tier-llm # LLM tier specific configuration
environment:
- TIER=llm
- MAX_CONCURRENT_REQUESTS=${MAX_CONCURRENT_REQUESTS:-50}

# Media Tier Environment
x-env-tier-media: &env-tier-media
<<: *pmoves-env-base
env_file:
- env.shared
- env.tier-media # Media tier specific configuration
environment:
- TIER=media
- GPU_ENABLED=${GPU_ENABLED:-true}
- MAX_CONCURRENT_JOBS=${MAX_CONCURRENT_JOBS:-4}

# UI Tier Environment
x-env-tier-ui: &env-tier-ui
<<: *pmoves-env-base
env_file:
- env.shared
- env.tier-ui # UI tier specific configuration
environment:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

env_file won’t load the current env.shared / env.tier-* scripts.
Line 18-97 uses env_file, but Compose expects dotenv KEY=VALUE files (no export, no ${VAR:-default} evaluation). Also env.tier-agent doesn’t match env.tier-agent.sh, so it won’t be found. This will leave containers missing the intended defaults.

✅ One possible fix (align to dotenv files)
 x-pmoves-env: &pmoves-env-base
   env_file:
-    - env.shared      # Base PMOVES.AI configuration
+    - env.shared.env  # Dotenv format (KEY=VALUE)

 x-env-tier-agent: &env-tier-agent
   <<: *pmoves-env-base
   env_file:
-    - env.shared
-    - env.tier-agent  # Agent tier specific configuration
+    - env.shared.env
+    - env.tier-agent.env

If you want to keep the .sh scripts, remove env_file and require source env.shared && source env.tier-agent.sh before docker compose up, or generate dotenv files from the scripts.

🤖 Prompt for AI Agents
In `@docker-compose.pmoves.yml` around lines 18 - 97, The docker-compose uses
env_file entries (x-pmoves-env / x-env-tier-*) pointing to script-style files
(env.shared, env.tier-agent, etc.) which won't be parsed as dotenv; either
convert those scripts into dotenv format (KEY=VALUE lines with no export or
${VAR:-default} expressions) and ensure filenames match (e.g., env.tier-agent ->
env.tier-agent or update compose to env.tier-agent.sh), or stop using env_file
and instead source the .sh files before running compose (e.g., require "source
env.shared && source env.tier-agent.sh" prior to docker compose up) or add a
build step that generates proper dotenv files from the scripts; fix references
to env.tier-agent / env.tier-worker / env.tier-llm etc. so the filenames used in
env_file exactly match the filesystem.

Comment thread env.shared
Comment thread env.tier-agent.sh
Comment on lines +1 to +4
# PMOVES.AI Tier Environment: Agent
# For Agent and Orchestrator services (Agent Zero, Archon, etc.)
# Source after env.shared: source env.shared && source env.tier-agent.sh

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add a shell directive/shebang to satisfy Shellcheck (SC2148).
Line 1 lacks a declared shell, which can trigger CI failures.

✅ Suggested fix
+#!/usr/bin/env bash
+# shellcheck shell=bash
 # PMOVES.AI Tier Environment: Agent
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# PMOVES.AI Tier Environment: Agent
# For Agent and Orchestrator services (Agent Zero, Archon, etc.)
# Source after env.shared: source env.shared && source env.tier-agent.sh
#!/usr/bin/env bash
# shellcheck shell=bash
# PMOVES.AI Tier Environment: Agent
# For Agent and Orchestrator services (Agent Zero, Archon, etc.)
# Source after env.shared: source env.shared && source env.tier-agent.sh
🧰 Tools
🪛 Shellcheck (0.11.0)

[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.

(SC2148)

🤖 Prompt for AI Agents
In `@env.tier-agent.sh` around lines 1 - 4, env.tier-agent.sh is missing a shell
directive which triggers ShellCheck SC2148; add a POSIX-compatible shebang as
the first line of env.tier-agent.sh (for example using env to pick bash) so the
script has a declared shell and CI/ShellCheck will pass, and verify the file
starts with that line and is saved with proper line endings.

Comment thread envared
Comment on lines +51 to +63
export NEO4J_URL=${NEO4J_URL:-http://neo4j:7474}
export NEO4J_USERNAME=${NEO4J_USERNAME:-neo4j}
export NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4j}

# Meilisearch (Full-Text Search)
export MEILISEARCH_URL=${MEILISEARCH_URL:-http://meilisearch:7700}
export MEILISEARCH_API_KEY=${MEILISEARCH_API_KEY:-}

# MinIO (Object Storage)
export MINIO_ENDPOINT=${MINIO_ENDPOINT:-http://minio:9000}
export MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
export MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
export MINIO_REGION=${MINIO_REGION:-us-east-1}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid shipping default credentials in the shared base config.
Line 52-63 hard-codes well-known defaults (neo4j/neo4j, minioadmin), while Line 14 defaults PMOVES_ENV to production. This makes it easy to deploy with unsafe credentials.

🔒 Suggested hardening (force explicit overrides)
- export NEO4J_USERNAME=${NEO4J_USERNAME:-neo4j}
- export NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4j}
+ export NEO4J_USERNAME=${NEO4J_USERNAME:-}
+ export NEO4J_PASSWORD=${NEO4J_PASSWORD:-}

- export MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
- export MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
+ export MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-}
+ export MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export NEO4J_URL=${NEO4J_URL:-http://neo4j:7474}
export NEO4J_USERNAME=${NEO4J_USERNAME:-neo4j}
export NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4j}
# Meilisearch (Full-Text Search)
export MEILISEARCH_URL=${MEILISEARCH_URL:-http://meilisearch:7700}
export MEILISEARCH_API_KEY=${MEILISEARCH_API_KEY:-}
# MinIO (Object Storage)
export MINIO_ENDPOINT=${MINIO_ENDPOINT:-http://minio:9000}
export MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
export MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
export MINIO_REGION=${MINIO_REGION:-us-east-1}
export NEO4J_URL=${NEO4J_URL:-http://neo4j:7474}
export NEO4J_USERNAME=${NEO4J_USERNAME:-}
export NEO4J_PASSWORD=${NEO4J_PASSWORD:-}
# Meilisearch (Full-Text Search)
export MEILISEARCH_URL=${MEILISEARCH_URL:-http://meilisearch:7700}
export MEILISEARCH_API_KEY=${MEILISEARCH_API_KEY:-}
# MinIO (Object Storage)
export MINIO_ENDPOINT=${MINIO_ENDPOINT:-http://minio:9000}
export MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-}
export MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-}
export MINIO_REGION=${MINIO_REGION:-us-east-1}
🤖 Prompt for AI Agents
In `@envared` around lines 51 - 63, Remove hard-coded default credentials and
force explicit overrides: stop assigning defaults for NEO4J_USERNAME,
NEO4J_PASSWORD, MEILISEARCH_API_KEY, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY in
the env file (do not default to "neo4j"/"minioadmin"/empty API keys); instead
leave them unset or empty and add startup validation logic that checks these
environment variables and fails fast with a clear error if they are missing.
Also avoid defaulting PMOVES_ENV to "production" without explicit intent—require
it be set or validate allowed values at startup. Use the environment variable
names (NEO4J_USERNAME, NEO4J_PASSWORD, MEILISEARCH_API_KEY, MINIO_ACCESS_KEY,
MINIO_SECRET_KEY, PMOVES_ENV) to locate and change the assignments and to
implement the validation.

Comment thread pmoves_announcer/__init__.py
Comment thread pmoves_health/__init__.py
Comment on lines +4 to +9
Service discovery using the PMOVES service registry with fallback chain:
1. Environment variables (static overrides)
2. Supabase service catalog (dynamic, runtime)
3. NATS service announcements (real-time, cached)
4. Docker DNS (development fallback)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Documented fallback chain isn’t implemented.
The header lists Supabase and NATS resolution, but get_service_info only checks env and DNS. Either implement those steps or update the description to avoid misleading integrators.

🤖 Prompt for AI Agents
In `@pmoves_registry/__init__.py` around lines 4 - 9, The module header claims a
4-step fallback chain (env, Supabase, NATS, Docker DNS) but get_service_info
only uses environment variables and DNS; update the implementation or the
docstring to match reality. Either implement Supabase lookups and NATS
announcements in get_service_info (add a Supabase client call to query the
service catalog by service name and a NATS subscriber/cache lookup to check
recent announcements, using identifiable functions like get_service_info and any
existing cache/NATS helper), or simplify the module docstring to list only the
actually-implemented fallbacks (env and DNS) and remove Supabase/NATS from the
header. Ensure references to get_service_info and any new helpers are consistent
and add minimal error handling/logging around external calls.

Comment on lines +147 to +166
# 1. Check environment variable override
if env_url := _get_env_url(slug):
return ServiceInfo(
slug=slug,
name=f"{slug} (from env)",
description=f"Service URL from environment variable",
health_check_url=env_url,
default_port=default_port,
tier=ServiceTier.API, # Default tier
)

# 2. Fallback to DNS-based URL
fallback_url = _fallback_dns_url(slug, default_port)
return ServiceInfo(
slug=slug,
name=f"{slug} (fallback)",
description=f"Service resolved via Docker DNS fallback",
health_check_url=fallback_url,
default_port=default_port,
tier=ServiceTier.API,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Ensure env URLs map to a health-check URL.
Env vars like HIRAG_V2_URL are base URLs; check_service_health will hit the base and often 404. Append /healthz (or detect an existing health suffix) when building ServiceInfo from env.

🐛 Proposed fix
-    if env_url := _get_env_url(slug):
-        return ServiceInfo(
+    if env_url := _get_env_url(slug):
+        health_url = env_url.rstrip("/")
+        if not any(health_url.endswith(s) for s in ("/healthz", "/health", "/metrics", "/ping")):
+            health_url = f"{health_url}/healthz"
+        return ServiceInfo(
             slug=slug,
             name=f"{slug} (from env)",
             description=f"Service URL from environment variable",
-            health_check_url=env_url,
+            health_check_url=health_url,
             default_port=default_port,
             tier=ServiceTier.API,  # Default tier
         )
🤖 Prompt for AI Agents
In `@pmoves_registry/__init__.py` around lines 147 - 166, The env-override branch
that constructs ServiceInfo when _get_env_url(slug) returns a base URL must
ensure health_check_url points to a health endpoint rather than the bare base
(modify the ServiceInfo creation in the env block that builds
slug/name/health_check_url); detect if env_url already ends with a known health
suffix (e.g., "/health", "/healthz", "/status", "/ready") and use it as-is,
otherwise append "/healthz" (preserving any trailing slash behavior) before
assigning health_check_url so check_service_health won't 404.

Comment thread PMOVES.AI_INTEGRATION.md
Comment on lines +13 to +15
- `env.shared` - Base environment configuration
- `env.tier-agent` - AGENT tier specific configuration
- `chit/secrets_manifest_v2.yaml` - Add your service's required secrets
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Correct the env file name and hyphenate “tier-specific”.
The PR adds env.tier-agent.sh, but the guide lists env.tier-agent, and “tier-specific” should be hyphenated.

✏️ Proposed fix
-- `env.tier-agent` - AGENT tier specific configuration
+- `env.tier-agent.sh` - AGENT tier-specific configuration
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `env.shared` - Base environment configuration
- `env.tier-agent` - AGENT tier specific configuration
- `chit/secrets_manifest_v2.yaml` - Add your service's required secrets
- `env.shared` - Base environment configuration
- `env.tier-agent.sh` - AGENT tier-specific configuration
- `chit/secrets_manifest_v2.yaml` - Add your service's required secrets
🧰 Tools
🪛 LanguageTool

[grammar] ~14-~14: Use a hyphen to join words.
Context: ...guration - env.tier-agent - AGENT tier specific configuration - `chit/secrets_m...

(QB_NEW_EN_HYPHEN)

🤖 Prompt for AI Agents
In `@PMOVES.AI_INTEGRATION.md` around lines 13 - 15, Update the docs to reference
the correct filename `env.tier-agent.sh` (replace the incorrect
`env.tier-agent`) and hyphenate “tier-specific” everywhere; locate the list
entry that currently reads `env.tier-agent - AGENT tier specific configuration`
and change it to `env.tier-agent.sh - AGENT tier-specific configuration`.

Comment thread PMOVES.AI_INTEGRATION.md
Comment on lines +73 to +78
- **Name:** Archon Agent Service
- **Slug:** archon
- **Tier:** agent
- **Port:** 8091
- **Health Check:** http://localhost:8091/healthz
- **NATS Enabled:** False
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid bare URLs in Markdown lists.
Wrap the URL in angle brackets (or link syntax) to satisfy MD034 and render consistently.

✏️ Proposed fix
-- **Health Check:** http://localhost:8091/healthz
+- **Health Check:** <http://localhost:8091/healthz>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Name:** Archon Agent Service
- **Slug:** archon
- **Tier:** agent
- **Port:** 8091
- **Health Check:** http://localhost:8091/healthz
- **NATS Enabled:** False
- **Name:** Archon Agent Service
- **Slug:** archon
- **Tier:** agent
- **Port:** 8091
- **Health Check:** <http://localhost:8091/healthz>
- **NATS Enabled:** False
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

77-77: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In `@PMOVES.AI_INTEGRATION.md` around lines 73 - 78, The markdown list item for
"Health Check" uses a bare URL which violates MD034; update the list item "-
**Health Check:** http://localhost:8091/healthz" to use angle-bracket or link
syntax (e.g., "- **Health Check:** <http://localhost:8091/healthz>" or "-
**Health Check:**
[http://localhost:8091/healthz](http://localhost:8091/healthz)") so the URL is
not bare and MD034 is satisfied.

- Fix deprecated datetime.utcnow() → datetime.now(timezone.utc)
- Fix YAML environment merge (list → map for proper merging)
- Fix health check decorator accumulation bug
- Fix health endpoint status codes (return 503 when unhealthy)
- Remove APP/UI tiers (stick to 6-tier architecture)
- Fix resource leaks in NATS connections (try/finally)
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@pmoves_announcer/__init__.py`:
- Around line 41-48: The ServiceTier enum is missing APP and UI which causes
ServiceAnnouncement.from_json (tier=ServiceTier(data["tier"])) to raise
ValueError for valid tiers; update ServiceTier to include "app" and "ui" entries
to match pmoves_registry, and change ServiceAnnouncement.from_json to rely on
Pydantic validation (e.g., parse_obj / model instantiation with a Field typed as
ServiceTier) instead of directly calling ServiceTier(...), so invalid values
produce Pydantic ValidationError rather than a bare ValueError.
- Around line 167-183: The current announce flow opens a NATS connection via
NATS.connect but if nc.publish() or nc.flush() raises the connection is never
closed; change the logic in the announce routine to only call NATS.connect
first, then wrap the publish/flush sequence in a try/finally so that await
nc.close() always runs when nc was successfully created; ensure nc is only
referenced if connect succeeded (e.g., set nc = None before connect, assign on
success) and guard the await nc.close() in the finally with a check and
swallow/log any errors from close so cleanup never leaks resources (refer to
NATS, connect, nc.publish, nc.flush, nc.close, create_announcement,
ServiceAnnouncement.SUBJECT).
♻️ Duplicate comments (2)
pmoves_announcer/__init__.py (2)

7-9: Fix module name in usage snippet.

The import example references service_announcer but the actual package is pmoves_announcer.

✏️ Proposed fix
-    from service_announcer import ServiceAnnouncer, announce_service
+    from pmoves_announcer import ServiceAnnouncer, announce_service

181-182: Don't print raw exception (may leak NATS credentials).

Using print(f"...{e}") can surface credentialized NATS URLs to stdout. Use structured logging without interpolating raw exceptions.

🔒 Proposed fix
+import logging
+
+logger = logging.getLogger(__name__)
...
-        except Exception as e:
-            print(f"Failed to announce service: {e}")
+        except Exception:
+            logger.exception("Failed to announce service")
             return False
🧹 Nitpick comments (5)
pmoves_announcer/__init__.py (2)

51-100: Consider using Pydantic for data validation.

The ServiceAnnouncement dataclass accepts untrusted data in from_json() without validation. Invalid data (wrong types, malformed URLs, negative ports) would be silently accepted. As per coding guidelines, use Pydantic to raise validation errors for data corruption.

♻️ Proposed refactor using Pydantic
-from dataclasses import dataclass, field, asdict
+from dataclasses import field
+from pydantic import BaseModel, Field, field_validator, HttpUrl
+from pydantic.dataclasses import dataclass

-@dataclass
-class ServiceAnnouncement:
+class ServiceAnnouncement(BaseModel):
     """
     Service announcement message format for NATS.
     """
-
     slug: str
     name: str
-    url: str
+    url: str  # or use HttpUrl for strict validation
     health_check: str
     tier: ServiceTier
-    port: int
-    timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
-    metadata: Dict[str, Any] = field(default_factory=dict)
+    port: int = Field(gt=0, le=65535)
+    timestamp: str = Field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
+    metadata: Dict[str, Any] = Field(default_factory=dict)
 
     # NATS subject for announcements
-    SUBJECT: str = "services.announce.v1"
+    SUBJECT: ClassVar[str] = "services.announce.v1"
 
     def to_json(self) -> str:
         """Convert to JSON for NATS publishing."""
-        data = {
-            "slug": self.slug,
-            ...
-        }
-        return json.dumps(data)
+        return self.model_dump_json()
 
     `@classmethod`
     def from_json(cls, data: str | dict) -> "ServiceAnnouncement":
         """Parse from JSON message."""
         if isinstance(data, str):
             data = json.loads(data)
-        return cls(
-            slug=data["slug"],
-            ...
-        )
+        return cls.model_validate(data)

279-283: Background loop silently swallows announce failures.

If announce() returns False or raises an exception, the loop continues without logging. This makes debugging difficult. Consider logging failures or implementing a failure threshold.

♻️ Proposed improvement
+import logging
+
+logger = logging.getLogger(__name__)
...
     async def _announce_loop(self):
         """Internal announcement loop."""
         while self._running:
-            await self.announcer.announce()
+            success = await self.announcer.announce()
+            if not success:
+                logger.warning("Background announcement failed, will retry next interval")
             await asyncio.sleep(self.interval)
pmoves_health/__init__.py (3)

30-33: HEALTH_CHECK_TIMEOUT constant is defined but unused.

The timeout constant (5.0s) is defined but individual checks use hardcoded values: HTTPCheck uses 2.0s (line 83), NATSCheck uses 2s (line 101). Consider using the constant for consistency.

♻️ Proposed fix
 class HTTPCheck(DependencyCheck):
     async def check(self) -> bool:
         try:
             import httpx
-            async with httpx.AsyncClient(timeout=2.0) as client:
+            async with httpx.AsyncClient(timeout=HEALTH_CHECK_TIMEOUT) as client:
                 response = await client.get(self.url)
                 return response.status_code == 200
...
 class NATSCheck(DependencyCheck):
     async def check(self) -> bool:
         nc = None
         try:
             from nats.aio.client import Client as NATS
-            nc = await NATS.connect(self.nats_url, connect_timeout=2)
+            nc = await NATS.connect(self.nats_url, connect_timeout=HEALTH_CHECK_TIMEOUT)

121-123: Duplicate checks not prevented.

add_check() appends without checking for duplicates. If the same check is added multiple times (e.g., via multiple decorators or init calls), it will execute repeatedly, slowing health checks.

♻️ Proposed fix
     def add_check(self, check: DependencyCheck) -> None:
         """Add a dependency check."""
+        # Prevent duplicate checks by name
+        if any(c.name == check.name for c in self.checks):
+            return
         self.checks.append(check)

163-168: Exceptions swallowed without logging.

Per retrieved learnings, exceptions should not be silently caught. Consider logging with logger.exception() for debugging while still returning the failed status.

Based on learnings: "Do not silently catch exceptions. Always log with logger.exception() or re-raise."

♻️ Proposed fix
+import logging
+
+logger = logging.getLogger(__name__)
...
             except Exception as e:
                 results[check.status_key()] = False
+                logger.debug("Health check '%s' failed: %s", check.name, type(e).__name__)
                 if check.required:
                     all_healthy = False
...
             except Exception:
                 results[name] = False
+                logger.debug("Custom health check '%s' failed", name, exc_info=True)
                 all_healthy = False

Also applies to: 177-179

Comment thread pmoves_announcer/__init__.py Outdated
Comment on lines +41 to +48
class ServiceTier(str, Enum):
"""PMOVES service tiers (6-tier architecture)."""
DATA = "data"
API = "api"
LLM = "llm"
MEDIA = "media"
AGENT = "agent"
WORKER = "worker"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find and display ServiceTier definitions in pmoves_announcer
find . -name "*.py" -path "*pmoves_announcer*" | head -20

Repository: POWERFULMOVES/PMOVES-Archon

Length of output: 101


🏁 Script executed:

# Search for ServiceTier and registry tier definitions
rg -n "class ServiceTier|ServiceTier\s*=" --type py -A 8 | head -100

Repository: POWERFULMOVES/PMOVES-Archon

Length of output: 1027


🏁 Script executed:

# Search for pmoves_registry tier definitions
rg -n "DATA|API|LLM|MEDIA|AGENT|WORKER|APP|UI" --type py -B 2 -A 2 | grep -A 10 "pmoves_registry" | head -50

Repository: POWERFULMOVES/PMOVES-Archon

Length of output: 2319


🏁 Script executed:

# Check for Pydantic usage and validation in the codebase
rg -n "pydantic|Pydantic|BaseModel|validator" --type py | head -50

Repository: POWERFULMOVES/PMOVES-Archon

Length of output: 4422


🏁 Script executed:

# Look at the actual pmoves_announcer/__init__.py file
cat -n pmoves_announcer/__init__.py | head -60

Repository: POWERFULMOVES/PMOVES-Archon

Length of output: 1855


🏁 Script executed:

# Check if ServiceAnnouncement uses Pydantic or just dataclass
cat -n pmoves_announcer/__init__.py | sed -n '51,100p'

Repository: POWERFULMOVES/PMOVES-Archon

Length of output: 2047


🏁 Script executed:

# Look for deserialization or announcement parsing logic
rg -n "ServiceAnnouncement|tier|from_dict|parse" pmoves_announcer/__init__.py -A 3 -B 1

Repository: POWERFULMOVES/PMOVES-Archon

Length of output: 4007


🏁 Script executed:

# Check if pmoves_registry ever creates announcements
rg -n "ServiceAnnouncer|ServiceAnnouncement" pmoves_registry/__init__.py -A 3 -B 1

Repository: POWERFULMOVES/PMOVES-Archon

Length of output: 53


🏁 Script executed:

# Look for any code that might deserialize tier values from strings
rg -n "ServiceTier\(" --type py -B 2 -A 2

Repository: POWERFULMOVES/PMOVES-Archon

Length of output: 1247


ServiceTier enum inconsistent with pmoves_registry; add Pydantic validation.

pmoves_registry defines 8 service tiers (lines 28-37), including APP and UI, but pmoves_announcer only defines 6 tiers (lines 41-48). When ServiceAnnouncement.from_json() deserializes a tier value at line 96 (tier=ServiceTier(data["tier"])), it will raise ValueError if the tier is APP or UI. Additionally, per coding guidelines, this file should use Pydantic to raise proper validation errors for data corruption instead of relying on bare Enum() conversion.

Either align the tier definitions or validate tier values with Pydantic before enum instantiation.

🤖 Prompt for AI Agents
In `@pmoves_announcer/__init__.py` around lines 41 - 48, The ServiceTier enum is
missing APP and UI which causes ServiceAnnouncement.from_json
(tier=ServiceTier(data["tier"])) to raise ValueError for valid tiers; update
ServiceTier to include "app" and "ui" entries to match pmoves_registry, and
change ServiceAnnouncement.from_json to rely on Pydantic validation (e.g.,
parse_obj / model instantiation with a Field typed as ServiceTier) instead of
directly calling ServiceTier(...), so invalid values produce Pydantic
ValidationError rather than a bare ValueError.

Comment on lines +167 to +183
try:
from nats.aio.client import Client as NATS

announcement = self.create_announcement()

nc = await NATS.connect(self.nats_url, connect_timeout=5)
await nc.publish(
ServiceAnnouncement.SUBJECT,
announcement.to_json().encode(),
)
await nc.flush()
await nc.close()

return True
except Exception as e:
print(f"Failed to announce service: {e}")
return False
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

NATS connection not closed on partial failure.

If nc.publish() or nc.flush() raises an exception after successful connect(), the connection is never closed, causing a resource leak. Use try/finally to ensure cleanup.

🐛 Proposed fix
     async def announce(self) -> bool:
         """Publish service announcement to NATS."""
+        nc = None
         try:
             from nats.aio.client import Client as NATS
 
             announcement = self.create_announcement()
 
             nc = await NATS.connect(self.nats_url, connect_timeout=5)
-            await nc.publish(
-                ServiceAnnouncement.SUBJECT,
-                announcement.to_json().encode(),
-            )
-            await nc.flush()
-            await nc.close()
-
-            return True
-        except Exception as e:
-            print(f"Failed to announce service: {e}")
+            try:
+                await nc.publish(
+                    ServiceAnnouncement.SUBJECT,
+                    announcement.to_json().encode(),
+                )
+                await nc.flush()
+                return True
+            finally:
+                await nc.close()
+        except Exception:
+            logger.exception("Failed to announce service")
             return False
🤖 Prompt for AI Agents
In `@pmoves_announcer/__init__.py` around lines 167 - 183, The current announce
flow opens a NATS connection via NATS.connect but if nc.publish() or nc.flush()
raises the connection is never closed; change the logic in the announce routine
to only call NATS.connect first, then wrap the publish/flush sequence in a
try/finally so that await nc.close() always runs when nc was successfully
created; ensure nc is only referenced if connect succeeded (e.g., set nc = None
before connect, assign on success) and guard the await nc.close() in the finally
with a check and swallow/log any errors from close so cleanup never leaks
resources (refer to NATS, connect, nc.publish, nc.flush, nc.close,
create_announcement, ServiceAnnouncement.SUBJECT).

- Neo4j: Remove neo4j:neo4j default credentials
- MinIO: Remove minioadmin:minioadmin default credentials
- ClickHouse: Remove tensorzero:tensorzero default credentials
- Fix typo: export_CACHE_TTL → export CACHE_TTL

Empty defaults now require explicit configuration for production use.
Phase 3: Code Quality
- Add pmoves_common shared types module (ServiceTier, HealthStatus)
- Update ServiceTier imports with fallback to shared module
- Remove duplicate ServiceTier enum definitions

Phase 4: Documentation
- Add comprehensive module docstrings to all integration modules
- Create .coderabbit.yaml for automated PR reviews
- Enable reviews on feat/* and fix/* branches
- Set docstring coverage target to 80%

This reduces code duplication and improves type consistency across
the PMOVES.AI ecosystem.
@POWERFULMOVES POWERFULMOVES merged commit 68f5458 into PMOVES.AI-Edition-Hardened Jan 21, 2026
1 check passed
POWERFULMOVES added a commit that referenced this pull request Feb 12, 2026
…altime

feat: LangExtract core + Hi‑RAG v2 hybrid, data IO, Supabase full, realtime UI, avatars
POWERFULMOVES pushed a commit that referenced this pull request Feb 12, 2026
- Add internal: true to pmoves_app network
- Add internal: true to pmoves_bus network
- Add internal: true to pmoves_monitoring network

Security: Isolates internal service communication from external access.
Services with published ports can still be accessed via host port mappings.

Related: Security review finding #3 - Network Isolation Misconfiguration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
POWERFULMOVES pushed a commit that referenced this pull request Feb 12, 2026
- Created PMOVES-DoX coleam00#96 for PostgreSQL 17 compatibility
- Created PMOVES-BoTZ coleam00#51 for TensorZero 2026 migration
- Created PMOVES-Agent-Zero #3 for PMOVES.AI integration patterns
- Fixed PMOVES-tensorzero to PMOVES.AI-Edition-Hardened branch
- Fixed Pmoves-hyperdimensions to PMOVES.AI-Edition-Hardened branch
- Verified PMOVES-Wealth on origin/main (fork with upstream)
- Cleaned up orphan e2b submodule reference
- Created PMOVES.AI-Edition-Hardened-DoX variant branches where needed
POWERFULMOVES pushed a commit that referenced this pull request Feb 12, 2026
- Marked all 3 PRs as merged (DoX coleam00#96, Agent-Zero #3, BoTZ coleam00#51)
- Documented feature branch restoration after merge
- Added merge conflict resolution details for BoTZ coleam00#51
- Documented keeping hardened MCP server implementation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
POWERFULMOVES added a commit that referenced this pull request Feb 12, 2026
* feat(pmoves-ai): Add PMOVES.AI integration patterns

- Add CHIT secrets manifest (chit/secrets_manifest_v2.yaml)
- Add tier-based environment loading (env.shared, env.tier-agent.sh)
- Add health check module (pmoves_health/)
- Add NATS service announcer (pmoves_announcer/)
- Add service registry client (pmoves_registry/)
- Add Docker Compose YAML anchors (docker-compose.pmoves.yml)
- Add integration documentation (PMOVES.AI_INTEGRATION.md)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(integration): Apply Phase 1 critical bug fixes

- Fix deprecated datetime.utcnow() → datetime.now(timezone.utc)
- Fix YAML environment merge (list → map for proper merging)
- Fix health check decorator accumulation bug
- Fix health endpoint status codes (return 503 when unhealthy)
- Remove APP/UI tiers (stick to 6-tier architecture)
- Fix resource leaks in NATS connections (try/finally)

* fix(security): Remove hardcoded credential defaults

- Neo4j: Remove neo4j:neo4j default credentials
- MinIO: Remove minioadmin:minioadmin default credentials
- ClickHouse: Remove tensorzero:tensorzero default credentials
- Fix typo: export_CACHE_TTL → export CACHE_TTL

Empty defaults now require explicit configuration for production use.

* refactor(code-quality): Phase 3 & 4 improvements

Phase 3: Code Quality
- Add pmoves_common shared types module (ServiceTier, HealthStatus)
- Update ServiceTier imports with fallback to shared module
- Remove duplicate ServiceTier enum definitions

Phase 4: Documentation
- Add comprehensive module docstrings to all integration modules
- Create .coderabbit.yaml for automated PR reviews
- Enable reviews on feat/* and fix/* branches
- Set docstring coverage target to 80%

This reduces code duplication and improves type consistency across
the PMOVES.AI ecosystem.

---------

Co-authored-by: POWERFULMOVES <POWERFULMOVES@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
POWERFULMOVES added a commit that referenced this pull request Apr 19, 2026
…gration (#12)

* Remove Docusaurus documentation system

Remove the standalone Docusaurus documentation website to simplify the project structure and reduce maintenance overhead.

Changes:
- Delete /docs directory (480MB freed) containing all Docusaurus files
- Remove docker-compose.docs.yml (optional docs service)
- Remove ARCHON_DOCS_PORT from .env.example
- Update .github/workflows/release-notes.yml (remove docs section)
- Update .github/test-release-notes.sh (remove docs section)

Preserved:
- Project documents feature (archon-ui-main/src/features/projects/documents/)
- Backend document service (python/src/server/services/projects/document_service.py)
- Project documents API endpoints (/api/projects/{id}/docs)

Benefits:
- Eliminates redundancy (content duplicated in /PRPs/ai_docs/)
- Reduces complexity (removes 480MB dependencies and configuration)
- Simplifies deployment (eliminates optional Docker service on port 3838)
- Lowers maintenance burden (single documentation source)

All validation tests passed:
✓ File system validation
✓ Backend imports verification
✓ Docker Compose integration testing
✓ CI/CD workflow validation
✓ Project documents API still functional

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add OpenRouter embeddings support

Implements OpenRouter as an embedding provider option, enabling access to multiple
embedding models (OpenAI, Google Gemini, Qwen3, Mistral) through a single API key.

Backend changes:
- Add validate_openrouter_api_key() for API key validation (sk-or-v1- format)
- Add OpenRouterErrorAdapter for error sanitization
- Add openrouter to valid providers in llm_provider_service
- Create openrouter_discovery_service with hardcoded model list
- Create /api/openrouter/models endpoint for model discovery
- Register OpenRouter router in FastAPI main app

Frontend changes:
- Create openrouterService.ts for model discovery API client
- Add OpenRouter to RAGSettings.tsx provider options
- Configure default models with provider prefix (openai/text-embedding-3-small)
- Add OpenRouter to embedding-capable providers list

Documentation:
- Update .env.example with OPENROUTER_API_KEY documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add unit tests for OpenRouter model discovery

Tests cover:
- Model list validation (non-empty, valid types)
- Provider prefix validation (all models have provider/)
- Data validation (positive dimensions, non-negative pricing)
- Provider validation (valid provider names)
- Specific provider models (OpenAI, Qwen)
- Model ID validation (requires prefix)

All 11 tests passing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix embedding provider grid to fit all providers in one line

Changed grid-cols-3 to grid-cols-4 for embedding provider selection
so all 4 embedding-capable providers (OpenAI, Google, OpenRouter, Ollama)
fit on one line, matching the chat provider layout.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix credential_service to recognize OpenRouter as embedding provider

Added 'openrouter' to embedding_capable_providers set in credential_service.py
to prevent it from being rejected and falling back to OpenAI.

Fixes: 'Invalid embedding provider openrouter doesn't support embeddings' error

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Address CodeRabbit review: Improve openrouterService robustness

1. Lazy initialization of baseUrl via getBaseUrl() method
   - Allows API URL to be updated at runtime without stale URL issues

2. Runtime validation of API response structure
   - Validates embedding_models array exists before caching
   - Prevents invalid responses from being cached

Addresses CodeRabbit nitpick comments on PR coleam00#852

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Delete PRPs/openrouter-embeddings-support.md

* Add robust cache validation with type guards in openrouterService

Implemented comprehensive validation to prevent crashes from corrupted cache:
- Created isCacheEntry() type guard to validate cache structure
- Parse JSON into unknown type (TypeScript strict mode compliant)
- Validate timestamp is number and data has OpenRouterModelListResponse shape
- Validate each model has all required fields with correct types
- Remove corrupted cache entries to avoid repeated failures
- No 'any' types used, full strict mode compliance

Prevents crashes from malformed cache data while maintaining type safety.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add comprehensive API response validation in discoverModels

Enhanced validation to catch malformed responses early:
- Validate total_count is non-negative number
- Verify total_count matches embedding_models.length
- Validate first model has required fields (id, provider, dimensions)
- Check dimensions are positive numbers
- Validate provider names are from expected set
- Provide specific error messages for each validation failure

Prevents caching invalid data and provides better debugging information.

Addresses CodeRabbit nitpick comment on PR coleam00#852

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Update README for Supabase service role key instructions (coleam00#836)

* chore(security): add CODEOWNERS and Dependabot configuration

Adds repository security files:
- CODEOWNERS for PR review routing
- dependabot.yml for automated security updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(hardened): Add nested submodule integrations for standalone operation

- Add .gitmodules with 7 nested integrations:
  - PMOVES-Agent-Zero (agent orchestration)
  - PMOVES-BoTZ (MCP tools)
  - PMOVES-HiRAG (knowledge retrieval)
  - PMOVES-Deep-Serch (deep research)
  - docling (document processing)
  - PMOVES-BotZ-gateway (MCP gateway)
  - PMOVES-tensorzero (TensorZero client)

- Fix PydanticAI Agent initialization (remove invalid result_type parameter)

Enables Archon to run standalone with PMOVES.AI service connections.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(pmoves): add Claude Code MCP adapter for PMOVES.AI integration

New module: python/pmoves_mcp/
- claude_code_adapter.py: Async MCP adapter for Claude Code CLI
- __init__.py: Module exports

Features:
- Execute TAC slash commands via Agent Zero's MCP interface
- ClaudeCodeMCPAdapter with async httpx client
- CommandResult dataclass for structured responses
- ARCHON_MCP_TOOLS registration for Archon integration

Available commands through adapter:
- /search:hirag, /search:supaserch, /search:deepresearch
- /health:check-all, /health:metrics
- /agents:status, /agents:mcp-query
- /deploy:smoke-test, /deploy:services, /deploy:up
- /botz:init, /botz:profile, /botz:mcp, /botz:secrets

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Restore fail-fast behavior for API key validation in upload

- Remove HTTPException catch that was allowing uploads to proceed with invalid credentials
- Aligns with beta guidelines: authentication failures should halt execution
- Addresses code review feedback from PR #1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(deps): Update uv.lock with dependency revisions

- Bump revision from 1 to 3
- Add upload-time fields for PyPI packages
- Sync with latest uv dependency resolution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(observability): add Prometheus metrics endpoint

Add /metrics endpoint for Prometheus scraping with:
- HTTP request counter (by method, endpoint, status)
- HTTP request duration histogram
- Knowledge operations counter
- MCP commands execution counter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(search): Add Hi-RAG v2 semantic expansion to keyword extraction

- Add optional Hi-RAG v2 integration for knowledge-aware keyword discovery
- Enable semantic keyword expansion via PMOVES knowledge graph
- Add hirag_url parameter to KeywordExtractor for knowledge graph queries
- Improves search relevance with ontology-driven term expansion

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(pmoves-ai): Add PMOVES.AI integration patterns (#3)

* feat(pmoves-ai): Add PMOVES.AI integration patterns

- Add CHIT secrets manifest (chit/secrets_manifest_v2.yaml)
- Add tier-based environment loading (env.shared, env.tier-agent.sh)
- Add health check module (pmoves_health/)
- Add NATS service announcer (pmoves_announcer/)
- Add service registry client (pmoves_registry/)
- Add Docker Compose YAML anchors (docker-compose.pmoves.yml)
- Add integration documentation (PMOVES.AI_INTEGRATION.md)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(integration): Apply Phase 1 critical bug fixes

- Fix deprecated datetime.utcnow() → datetime.now(timezone.utc)
- Fix YAML environment merge (list → map for proper merging)
- Fix health check decorator accumulation bug
- Fix health endpoint status codes (return 503 when unhealthy)
- Remove APP/UI tiers (stick to 6-tier architecture)
- Fix resource leaks in NATS connections (try/finally)

* fix(security): Remove hardcoded credential defaults

- Neo4j: Remove neo4j:neo4j default credentials
- MinIO: Remove minioadmin:minioadmin default credentials
- ClickHouse: Remove tensorzero:tensorzero default credentials
- Fix typo: export_CACHE_TTL → export CACHE_TTL

Empty defaults now require explicit configuration for production use.

* refactor(code-quality): Phase 3 & 4 improvements

Phase 3: Code Quality
- Add pmoves_common shared types module (ServiceTier, HealthStatus)
- Update ServiceTier imports with fallback to shared module
- Remove duplicate ServiceTier enum definitions

Phase 4: Documentation
- Add comprehensive module docstrings to all integration modules
- Create .coderabbit.yaml for automated PR reviews
- Enable reviews on feat/* and fix/* branches
- Set docstring coverage target to 80%

This reduces code duplication and improves type consistency across
the PMOVES.AI ecosystem.

---------

Co-authored-by: POWERFULMOVES <POWERFULMOVES@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* chore: Add GitHub Actions workflows and update submodule SHAs

- Add CI/CD workflows: ci.yml, claude-fix.yml, claude-review.yml, release-notes.yml
- Update submodule references to latest commits

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(pr): Address CodeRabbit review issues

- Fix dependabot.yml: Point pip to /python, npm to /archon-ui-main
- Add branch = main to docling submodule in .gitmodules
- Add prometheus-client>=0.20.0 to all dependency group

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: Sync main to hardened - MCP adapter, CODEOWNERS, nested submodules, persona service

Syncs 4 commits from main to PMOVES.AI-Edition-Hardened:

- Claude Code MCP adapter for PMOVES.AI integration
- CODEOWNERS configuration (security)
- Nested submodule integrations for standalone operation
- Persona service and API routes for agent creation

Includes CodeRabbit review fixes:
- Fixed route ordering (/thread-types before /{persona_id})
- Added proper error handling and validation
- Removed Git conflict markers
- Fixed .coderabbit.yaml configuration

🤖 Generated with Claude Code

* docs: add PMOVES.AI skill hints context tags

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(submodules): update nested PMOVES-HiRAG submodule pointer

* security: update PBKDF2 iterations to 600,000

* fix: correct indentation in state_reconciliation.py if-block

* fix(env): strip export syntax and add NATS auth to env.shared defaults

- Remove `export` prefix from all variables (incompatible with Docker env_file)
- Update NATS_URL default to include pmoves credentials
- Update usage comment to reflect Docker Compose env_file pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(claude): add CHIT-aware integration context (#9)

Co-authored-by: Shaela Bello <slbello@uncg.edu>

* fix(auth): align NATS default URLs with credentialed runtime (#10)

Co-authored-by: Shaela Bello <slbello@uncg.edu>

* chore(submodules): sync HiRAG and BotZ gateway pointers (#11)

Co-authored-by: Shaela Bello <slbello@uncg.edu>

* fix(security): add USER directive to archon-ui Dockerfile

Run as non-root user (uid 65532) to satisfy BuildKit audit and
defense-in-depth container hardening requirements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(github): add GitHub App token minting and client

Implements GitHub App integration for agent work orders with:
- Token minting with JWT RS256 signing (10-min lifetime)
- Installation token exchange via GitHub API
- Token caching with 50-minute expiry window
- GitHubClient with App token + gh CLI fallback
- Full test coverage for token minting and PR operations

Environment variables required:
- GH_APP_ID: GitHub App numeric ID
- GH_APP_SEC: PEM private key (handles double-escaped env values)
- GH_APP_INSTALLATION_ID: Installation ID for org access

Key features:
- mint_installation_token(): Creates short-lived JWT + exchanges for token
- get_installation_token(): Cached token retrieval with force_refresh option
- clear_token_cache(): Manual cache invalidation
- GitHubClient.list_pull_requests(): API-first with CLI fallback
- Graceful degradation when credentials unavailable

Security considerations:
- PEM keys stored in env.tier-agent (plaintext - production hardening needed)
- No persistent token storage (in-memory cache only)
- Short-lived tokens (JWT <10min, installation tokens = 1 hour)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore(submodules): promote nested submodule pointers (HiRAG, BotZ-gateway)

- external/PMOVES-HiRAG: 89d4abf→e904b12 (CHIT + geometry bus context, PR #4)
- pmoves_multi_agent_pro_pack/PMOVES-BotZ-gateway: 40e1e33→2565022 (log sanitizer, PR #4)

Both commits are merged on their respective origin/main branches.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore(submodules): recover nested wipes + promote BoTZ skill pointers

- Recovered 3 wiped nested subs: Deep-Serch (88 files), tensorzero
  (2906 files), docling (839 files) — same wipe pattern as Phase 5
- Recovered 6 wiped sub-sub-subs inside nested BoTZ copy
- Promoted 7 skill repo pointer advances in nested BoTZ copy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: leex279 <thomas@thirty3.de>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: sean-eskerium <sean@eskerium.com>
Co-authored-by: Jason Pickens <jasonpickensnz@gmail.com>
Co-authored-by: POWERFULMOVES <POWERFULMOVES@users.noreply.github.com>
Co-authored-by: PMOVES.AI <claude@pmoves.ai>
Co-authored-by: Shaela Bello <slbello@uncg.edu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant